#include <gtk/gtk.h>
#include "mywidget.h"

///////////////////////////////////////////////////////////////////////////////
// GestureSignalType
//

GType gesture_signal_type_get_type(void)
{
  static volatile gsize g_define_type_id__volatile = 0;

  if (g_once_init_enter (&g_define_type_id__volatile))
    {
      static const GEnumValue values[] = {
        { GESTURE_SIG_0, "GESTURE_SIG_0", "0" },
        { GESTURE_SIG_BEGIN, "GESTURE_SIG_BEGIN", "gesture-begin" },
        { GESTURE_SIG_CANCEL, "GESTURE_SIG_CANCEL", "gesture-cancel" },
        { GESTURE_SIG_END, "GESTURE_SIG_END", "gesture-end" },
        { GESTURE_SIG_SEQUENCE_STATE_CHANGED, "GESTURE_SIG_SEQUENCE_STATE_CHANGED", "gesture-sequence-state-changed" },
        { GESTURE_SIG_UPDATE, "GESTURE_SIG_UPDATE", "gesture-update" },
        { GESTURE_SIG_MULTIPRESS_PRESSED, "GESTURE_SIG_MULTIPRESS_PRESSED", "multipress-pressed" },
        { GESTURE_SIG_MULTIPRESS_RELEASED, "GESTURE_SIG_MULTIPRESS_RELEASED", "multipress-released" },
        { GESTURE_SIG_MULTIPRESS_STOPPED, "GESTURE_SIG_MULTIPRESS_STOPPED", "multipress-stopped" },
        { GESTURE_SIG_LONGPRESS_PRESSED, "GESTURE_SIG_LONGPRESS_PRESSED", "longpress-pressed" },
        { GESTURE_SIG_LONGPRESS_CANCELLED, "GESTURE_SIG_LONGPRESS_CANCELLED", "longpress-cancelled" },
        { GESTURE_SIG_DRAG_BEGIN, "GESTURE_SIG_DRAG_BEGIN", "drag-begin" },
        { GESTURE_SIG_DRAG_UPDATE, "GESTURE_SIG_DRAG_UPDATE", "drag-update" },
        { GESTURE_SIG_DRAG_END, "GESTURE_SIG_DRAG_END", "drag-end" },
        { GESTURE_SIG_KEY_FOCUS_IN, "GESTURE_SIG_KEY_FOCUS_IN", "key-focus-in" },
        { GESTURE_SIG_KEY_FOCUS_OUT, "GESTURE_SIG_KEY_FOCUS_OUT", "key-focus-out" },
        { GESTURE_SIG_KEY_IM_UPDATE, "GESTURE_SIG_KEY_IM_UPDATE", "key-im-update" },
        { GESTURE_SIG_KEY_PRESSED, "GESTURE_SIG_KEY_PRESSED", "key-pressed" },
        { GESTURE_SIG_KEY_RELEASED, "GESTURE_SIG_KEY_RELEASED", "key-released" },
        { GESTURE_SIG_KEY_MODIFIERS, "GESTURE_SIG_KEY_MODIFIERS", "key-modifiers" },
        { GESTURE_SIG_SCROLL_DECELERATE, "GESTURE_SIG_SCROLL_DECELERATE", "scroll-decelerate" },
        { GESTURE_SIG_SCROLL_BEGIN, "GESTURE_SIG_SCROLL_BEGIN", "scroll-begin" },
        { GESTURE_SIG_SCROLL_SCROLL, "GESTURE_SIG_SCROLL_SCROLL", "scroll-scroll" },
        { GESTURE_SIG_SCROLL_END, "GESTURE_SIG_SCROLL_END", "scroll-end" },
        { GESTURE_SIG_MOTION_ENTER, "GESTURE_SIG_MOTION_ENTER", "motion-enter" },
        { GESTURE_SIG_MOTION_MOTION, "GESTURE_SIG_MOTION_MOTION", "motion-motion" },
        { GESTURE_SIG_MOTION_LEAVE, "GESTURE_SIG_MOTION_LEAVE", "motion-leave" },
        { 0, NULL, NULL }
      };

      GType g_define_type_id =
        g_enum_register_static (g_intern_static_string ("GestureSignalType"), values);
      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
    }

  return g_define_type_id__volatile;
}


///////////////////////////////////////////////////////////////////////////////
// MyWidget
//

GType
gtk_event_sequence_state_get_type (void)
{
  static volatile gsize g_define_type_id__volatile = 0;

  if (g_once_init_enter (&g_define_type_id__volatile))
    {
      static const GEnumValue values[] = {
        { GTK_EVENT_SEQUENCE_NONE, "GTK_EVENT_SEQUENCE_NONE", "none" },
        { GTK_EVENT_SEQUENCE_CLAIMED, "GTK_EVENT_SEQUENCE_CLAIMED", "claimed" },
        { GTK_EVENT_SEQUENCE_DENIED, "GTK_EVENT_SEQUENCE_DENIED", "denied" },
        { 0, NULL, NULL }
      };
      GType g_define_type_id =
        g_enum_register_static (g_intern_static_string ("GtkEventSequenceState"), values);
      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
    }

  return g_define_type_id__volatile;
}







//enum and struct

enum {
    PROP_0,
    PROP_LABEL,

    LAST_PROP
};

enum {
    GESTURE_SIGNAL,

    LAST_SIGNAL
};


//variables

static GParamSpec *props[LAST_PROP] = { NULL, };
#define PARAM_SPEC_PARAM_ID(pspec)              ((pspec)->param_id)
#define PARAM_SPEC_SET_PARAM_ID(pspec, id)      ((pspec)->param_id = (id))

static guint signals[LAST_SIGNAL] = { 0 };

static gint mywidget_private_offset;        //用于定位instance中的private.
static gpointer mywidget_parent_class = NULL;


//declaration of static functions

static void mywidget_marshal_VOID__ENUM_INT_INT(GClosure     *closure,
                                          GValue       *return_value,
                                          guint         n_param_values,
                                          const GValue *param_values,
                                          gpointer      invocation_hint,
                                          gpointer      marshal_data);

static void mywidget_marshal_VOID__ENUM_INT_INTv(GClosure *closure,
                                GValue   *return_value G_GNUC_UNUSED,
                                gpointer  instance,
                                va_list   args,
                                gpointer  marshal_data,
                                int       n_params,
                                GType    *param_types);



static void mywidget_base_class_init(MyWidgetClass *klass);
static void mywidget_base_class_finalize(MyWidgetClass *klass);
static void mywidget_class_init(MyWidgetClass *klass);
static void mywidget_init(MyWidget *my_widget);



static void mywidget_constructed(GObject *object);
static void mywidget_finalize(GObject *object);
static void mywidget_set_property(GObject            *object,
                                  guint               prop_id,
                                  const GValue       *value,
                                  GParamSpec         *pspec);
static void mywidget_get_property(GObject            *object,
                                  guint               prop_id,
                                  GValue             *value,
                                  GParamSpec         *pspec);
static void mywidget_get_preferred_width(GtkWidget           *widget,
                                         gint                *minimum_size,
                                         gint                *natural_size);
static void mywidget_get_preferred_height(GtkWidget           *widget,
                                          gint                *minimum_size,
                                          gint                *natural_size);

static void mywidget_size_allocate(GtkWidget * widget, GtkAllocation * allocation);
static gint mywidget_draw(GtkWidget * widget, cairo_t *cr);
static void mywidget_realize(GtkWidget * widget);
static void mywidget_unrealize(GtkWidget * widget);
static void mywidget_map(GtkWidget * widget);
static void mywidget_unmap(GtkWidget * widget);
static void mywidget_gesture_signal(MyWidget *widget, GestureSignalType sig_type, gint x, gint y);


static void	gesture_begin_cb(GtkGesture *gesture, GdkEventSequence *sequence, MyWidget *my_widget);
static void	gesture_cancel_cb(GtkGesture *gesture, GdkEventSequence *sequence, MyWidget *my_widget);
static void	gesture_end_cb(GtkGesture *gesture, GdkEventSequence *sequence, MyWidget *my_widget);
static void	gesture_sequence_state_changed_cb(GtkGesture *gesture, GdkEventSequence *sequence, GtkEventSequenceState state, MyWidget *my_widget);
static void	gesture_update_cb(GtkGesture *gesture, GdkEventSequence *sequence, MyWidget *my_widget);
static void multipress_gesture_pressed_cb(GtkGestureMultiPress *gesture,
                       guint                 n_press,
                       gdouble               x,
                       gdouble               y,
                       MyWidget *my_widget);
static void multipress_gesture_released_cb(GtkGestureMultiPress *gesture,
                        guint                 n_press,
                        gdouble               x,
                        gdouble               y,
                        MyWidget *my_widget);
static void multipress_gesture_stopped_cb(GtkGestureMultiPress *gesture, MyWidget *my_widget);
static void longpress_gesture_pressed_cb(GtkGestureLongPress *gesture, double x, double y, MyWidget *my_widget);
static void longpress_gesture_cancelled_cb(GtkGestureLongPress *gesture, MyWidget *my_widget);
static void drag_gesture_begin_cb(GtkGestureDrag *gesture, double start_x, double start_y, MyWidget *my_widget);
static void drag_gesture_update_cb(GtkGestureDrag *gesture, double offset_x, double offset_y, MyWidget *my_widget);
static void drag_gesture_end_cb(GtkGestureDrag *gesture, double offset_x, double offset_y, MyWidget *my_widget);
static void key_event_controller_focus_in_cb(GtkEventControllerKey *eventcontrollerkey, MyWidget *my_widget);
static void key_event_controller_focus_out_cb(GtkEventControllerKey *eventcontrollerkey, MyWidget *my_widget);
static void key_event_controller_im_update_cb(GtkEventControllerKey *eventcontrollerkey, MyWidget *my_widget);
static gboolean key_event_controller_key_pressed_cb(GtkEventControllerKey *controller, 
                                              guint                  keyval,
                                              guint                  keycode,
                                              GdkModifierType        state,
                                              MyWidget              *my_widget);
static gboolean key_event_controller_key_released_cb(GtkEventControllerKey *controller, 
                                              guint                  keyval,
                                              guint                  keycode,
                                              GdkModifierType        state,
                                              MyWidget              *my_widget);
static gboolean key_event_controller_modifiers_cb(GtkEventControllerKey *eventcontrollerkey,
                                              GdkModifierType        arg1,
                                              MyWidget              *my_widget);
static void motion_event_controller_enter_cb(GtkEventControllerMotion *controller,
                                              double                    x,
                                              double                    y,
                                              MyWidget              *my_widget);
static void motion_event_controller_leave_cb(GtkEventControllerMotion *controller,
                                              MyWidget              *my_widget);
static void motion_event_controller_motion_cb(GtkEventControllerMotion *controller,
                                              double                    x,
                                              double                    y,
                                              MyWidget              *my_widget);
static void scroll_event_controller_decelerate_cb (GtkEventControllerScroll *controller,
                                              double                    vel_x,
                                              double                    vel_y,
                                              MyWidget              *my_widget);
static void scroll_event_controller_scroll_cb (GtkEventControllerScroll *controller,
                                              double                    dx,
                                              double                    dy,
                                              MyWidget              *my_widget);
static void scroll_event_controller_scroll_begin_cb (GtkEventControllerScroll *controller,
                                              MyWidget              *my_widget);
static void scroll_event_controller_scroll_end_cb (GtkEventControllerScroll *controller,
                                              MyWidget              *my_widget);


//implemention of functions

static inline gpointer mywidget_get_instance_private (MyWidget *self)
{
  return G_STRUCT_MEMBER_P(self, mywidget_private_offset);
}

GType mywidget_get_type (void)		
{
  static GType mywidget_type = 0;

  if (!mywidget_type)       //lazy creation
    {
      const GTypeInfo type_info =
      {
        sizeof (MyWidgetClass),
        (GBaseInitFunc) mywidget_base_class_init,                   //base_class_init()
        (GBaseFinalizeFunc) mywidget_base_class_finalize,           //base_class_finalize()
        (GClassInitFunc) mywidget_class_init,                       //class_init()
        NULL,                                                        //class_finalize
        NULL,                                                       //class_data
        sizeof (MyWidget),                                          //instance size
        0,                                                           //n_preallocs
        (GInstanceInitFunc) mywidget_init,                          //instance_init
        NULL,                                                       //value_table
      };

      mywidget_type = g_type_register_static (GTK_TYPE_BIN, "MyWidget", &type_info, 0);

      //add classPrivate
      g_type_add_class_private(mywidget_type, sizeof (MyWidgetClassPrivate));

      //the offset of MyWidgetPriv* in MyWidget
      mywidget_private_offset = g_type_add_instance_private(mywidget_type, sizeof(MyWidgetPrivate));
    }

  return mywidget_type;
}

static void mywidget_base_class_init(MyWidgetClass *klass)
{
  klass->priv = G_TYPE_CLASS_GET_PRIVATE(klass, TYPE_MYWIDGET, MyWidgetClassPrivate);
}


static void mywidget_base_class_finalize(MyWidgetClass *klass)
{
    //free the classPrivate. 
    //nothing to do here.
}



static void mywidget_class_init(MyWidgetClass *klass)
{
    g_print("mywidget_class_init.....\n");
    
    GObjectClass *object_class;
    GtkWidgetClass *widget_class;
    // GtkContainerClass *container_class;

    object_class = G_OBJECT_CLASS(klass);
    widget_class = GTK_WIDGET_CLASS(klass);
    // container_class = GTK_CONTAINER_CLASS(klass);

    mywidget_parent_class = g_type_class_peek_parent(klass);
    g_type_class_adjust_private_offset(klass, &mywidget_private_offset);

    //
    //set methods
    //

    object_class->set_property = mywidget_set_property;
    object_class->get_property = mywidget_get_property;
    object_class->constructed = mywidget_constructed;
    object_class->finalize = mywidget_finalize;

    widget_class->get_preferred_width = mywidget_get_preferred_width;
    widget_class->get_preferred_height = mywidget_get_preferred_height;
    widget_class->size_allocate = mywidget_size_allocate;
    widget_class->realize = mywidget_realize;
    widget_class->unrealize = mywidget_unrealize;
    widget_class->map = mywidget_map;
    widget_class->unmap = mywidget_unmap;
    widget_class->draw = mywidget_draw;

    //gtkContainer and gtkBin have no change.

    klass->gesture_signal = mywidget_gesture_signal;

    //
    //set props
    //

    props[PROP_LABEL] =
      g_param_spec_string ("label",
                            "Label",
                            "Text abel widget inside the button, if the button contains a label widget",
                            NULL,
                            G_PARAM_READWRITE|G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY);
    g_object_class_install_properties (object_class, LAST_PROP, props);

    //
    //set signals
    //

    signals[GESTURE_SIGNAL] =
        g_signal_new ("gesture-signal",
                      G_TYPE_FROM_CLASS (klass),
                      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                      G_STRUCT_OFFSET(MyWidgetClass, gesture_signal),
                      NULL, /* accumulator */
                      NULL, /* accu_data */
                      mywidget_marshal_VOID__ENUM_INT_INT,
                      G_TYPE_NONE,
                      3,
                      TYPE_GESTURE_SIGNAL, G_TYPE_INT, G_TYPE_INT);
    g_signal_set_va_marshaller (signals[GESTURE_SIGNAL],
                              G_TYPE_FROM_CLASS (klass),
                              mywidget_marshal_VOID__ENUM_INT_INTv);


  //
  //binding keys
  //

  //
  //install style property
  //




}

static void mywidget_init(MyWidget *my_widget)
{
   g_print("mywidget_init.....\n");
    

  GtkWidget *widget;
  widget = GTK_WIDGET(my_widget);

  gtk_widget_set_can_focus(widget, TRUE);       
  gtk_widget_set_receives_default(widget, TRUE);		//zf, button可以接受成为default
  gtk_widget_set_has_window(widget, FALSE);


  MyWidgetPrivate *priv;
  priv = mywidget_get_instance_private(my_widget);
  my_widget->priv = priv;
  //以上等同于
  //priv = my_widget->priv = G_TYPE_INSTANCE_GET_PRIVATE (my_widget,
                                              // TYPE_MYWIDGET,
                                              // MyWidgetPrivate);


  priv->label_text = NULL;
  priv->last_type = GESTURE_SIG_0;
  priv->event_window = NULL;

  priv->multipress_gesture = NULL;
  priv->drag_gesture = NULL;
  priv->longpress_gesture = NULL;
  priv->key_event_controller = NULL;
  priv->motion_event_controller = NULL;
  priv->scroll_event_controller = NULL;

  /* Note: Order is important here.
   * The ::drag-begin handler relies on the state set up by the
   * multipress ::pressed handler. Gestures are handling events
   * in the oppposite order in which they are added to their
   * widget.
   */
  //通常, multipress gesture放在drag gesture后面创建. 因为app一般有赖于multipress::pressed建立drag场景.

#if 1
  priv->drag_gesture = gtk_gesture_drag_new(widget);
  gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (priv->drag_gesture), 0);
  g_signal_connect (priv->drag_gesture, "drag-begin",
                    G_CALLBACK (drag_gesture_begin_cb), my_widget);
  g_signal_connect (priv->drag_gesture, "drag-update",
                    G_CALLBACK (drag_gesture_update_cb), my_widget);
  g_signal_connect (priv->drag_gesture, "drag-end",
                    G_CALLBACK (drag_gesture_end_cb), my_widget);
  g_assert(GTK_IS_EVENT_CONTROLLER(priv->drag_gesture));
#endif

#if 1
  priv->multipress_gesture = gtk_gesture_multi_press_new(widget);
  gtk_gesture_single_set_touch_only(GTK_GESTURE_SINGLE(priv->multipress_gesture), FALSE);
  gtk_gesture_single_set_exclusive(GTK_GESTURE_SINGLE (priv->multipress_gesture), TRUE);
  gtk_gesture_single_set_button(GTK_GESTURE_SINGLE (priv->multipress_gesture), GDK_BUTTON_PRIMARY);
  gtk_gesture_group(priv->drag_gesture, priv->multipress_gesture);
  g_signal_connect(priv->multipress_gesture, "begin", G_CALLBACK (gesture_begin_cb), my_widget);
  g_signal_connect(priv->multipress_gesture, "cancel", G_CALLBACK (gesture_cancel_cb), my_widget);
  g_signal_connect(priv->multipress_gesture, "end", G_CALLBACK (gesture_end_cb), my_widget);
  g_signal_connect(priv->multipress_gesture, "update", G_CALLBACK (gesture_update_cb), my_widget);
  g_signal_connect(priv->multipress_gesture, "sequence-state-changed", G_CALLBACK (gesture_sequence_state_changed_cb), my_widget);
  g_signal_connect(priv->multipress_gesture, "update", G_CALLBACK (gesture_update_cb), my_widget);
  g_signal_connect(priv->multipress_gesture, "pressed", G_CALLBACK (multipress_gesture_pressed_cb), my_widget);
  g_signal_connect(priv->multipress_gesture, "released", G_CALLBACK (multipress_gesture_released_cb), my_widget);
  g_signal_connect(priv->multipress_gesture, "stopped", G_CALLBACK (multipress_gesture_stopped_cb), my_widget);
  gtk_event_controller_set_propagation_phase(GTK_EVENT_CONTROLLER (priv->multipress_gesture), GTK_PHASE_BUBBLE);
  g_assert(GTK_IS_EVENT_CONTROLLER(priv->multipress_gesture));
  // g_assert(widget == gtk_event_controller_get_widget(priv->multipress_gesture));
#endif

#if 1
  priv->longpress_gesture = gtk_gesture_long_press_new(widget);
  g_object_set(priv->longpress_gesture, "delay-factor", 2.0, NULL);
  gtk_gesture_group(priv->drag_gesture, priv->longpress_gesture);
  g_signal_connect(priv->longpress_gesture, "pressed",
                    G_CALLBACK(longpress_gesture_pressed_cb), my_widget);
  g_signal_connect(priv->longpress_gesture, "cancelled",
                    G_CALLBACK(longpress_gesture_cancelled_cb), my_widget);
  g_assert(GTK_IS_EVENT_CONTROLLER(priv->longpress_gesture));

#endif

  //keyEventController等需要设置gtk_widget_set_can_focus()
#if 1
  priv->key_event_controller = gtk_event_controller_key_new(widget);
  g_signal_connect (priv->key_event_controller, "focus-in",
                    G_CALLBACK (key_event_controller_focus_in_cb), my_widget);
  g_signal_connect (priv->key_event_controller, "focus-out",
                    G_CALLBACK (key_event_controller_focus_out_cb), my_widget);
  g_signal_connect (priv->key_event_controller, "im-update",
                    G_CALLBACK (key_event_controller_im_update_cb), my_widget);
  g_signal_connect (priv->key_event_controller, "key-pressed",
                    G_CALLBACK (key_event_controller_key_pressed_cb), my_widget);
  g_signal_connect (priv->key_event_controller, "key-released",
                    G_CALLBACK (key_event_controller_key_released_cb), my_widget);
  g_signal_connect (priv->key_event_controller, "modifiers",
                    G_CALLBACK (key_event_controller_modifiers_cb), my_widget);
  g_assert(GTK_IS_EVENT_CONTROLLER(priv->key_event_controller));

  priv->motion_event_controller = gtk_event_controller_motion_new(widget);
  g_signal_connect (priv->motion_event_controller, "enter",
                    G_CALLBACK (motion_event_controller_enter_cb), my_widget);
  g_signal_connect (priv->motion_event_controller, "leave",
                    G_CALLBACK (motion_event_controller_leave_cb), my_widget);
  g_signal_connect (priv->motion_event_controller, "motion",
                    G_CALLBACK (motion_event_controller_motion_cb), my_widget);
  g_assert(GTK_IS_EVENT_CONTROLLER(priv->motion_event_controller));

  priv->scroll_event_controller = gtk_event_controller_scroll_new(widget, GTK_EVENT_CONTROLLER_SCROLL_HORIZONTAL);
  g_signal_connect (priv->scroll_event_controller, "decelerate",
                    G_CALLBACK (scroll_event_controller_decelerate_cb), my_widget);
  g_signal_connect (priv->scroll_event_controller, "scroll",
                    G_CALLBACK (scroll_event_controller_scroll_cb), my_widget);
  g_signal_connect (priv->scroll_event_controller, "scroll-begin",
                    G_CALLBACK (scroll_event_controller_scroll_begin_cb), my_widget);
  g_signal_connect (priv->scroll_event_controller, "scroll-end",
                    G_CALLBACK (scroll_event_controller_scroll_end_cb), my_widget);
  g_assert(GTK_IS_EVENT_CONTROLLER(priv->scroll_event_controller));
#endif
}




GtkWidget* mywidget_new(void)
{
  g_print("mywidget_new.....\n");
    
  GtkWidget *widget = NULL;
  widget = g_object_new(TYPE_MYWIDGET, NULL);
  return widget;
}

//marshaller
static void mywidget_marshal_VOID__ENUM_INT_INT(GClosure     *closure,
                                          GValue       *return_value,
                                          guint         n_param_values,
                                          const GValue *param_values,
                                          gpointer      invocation_hint,
                                          gpointer      marshal_data)
{
  typedef void (*GMarshalFunc_VOID__ENUM_INT_INT) (gpointer data1,
                                                 gint arg1,
                                                 gint arg2,
                                                 gint arg3,
                                                 gpointer data2);
  GCClosure *cc = (GCClosure *) closure;
  gpointer data1, data2;
  GMarshalFunc_VOID__ENUM_INT_INT callback;

  g_return_if_fail (n_param_values == 4);

  if (G_CCLOSURE_SWAP_DATA (closure))
    {
      data1 = closure->data;
      data2 = g_value_peek_pointer (param_values + 0);
    }
  else
    {
      data1 = g_value_peek_pointer (param_values + 0);
      data2 = closure->data;
    }
  callback = (GMarshalFunc_VOID__ENUM_INT_INT) (marshal_data ? marshal_data : cc->callback);

  callback (data1,
            g_value_get_enum (param_values + 1),
            g_value_get_int (param_values + 2),
            g_value_get_int (param_values + 3),
            data2);  
}

//marshaller
static void mywidget_marshal_VOID__ENUM_INT_INTv(GClosure *closure,
                                GValue   *return_value G_GNUC_UNUSED,
                                gpointer  instance,
                                va_list   args,
                                gpointer  marshal_data,
                                int       n_params,
                                GType    *param_types)
{
  typedef void (*GMarshalFunc_VOID__ENUM_INT_INT) (gpointer data1,
                                                 gint arg1,
                                                 gint arg2,
                                                 gint arg3,
                                                 gpointer data2);
  GCClosure *cc = (GCClosure *) closure;
  gpointer data1, data2;
  GMarshalFunc_VOID__ENUM_INT_INT callback;
  gint arg0;
  gint arg1;
  gint arg2;
  va_list args_copy;

  G_VA_COPY (args_copy, args);

  arg0 = (gint) va_arg (args_copy, gint);
  arg1 = (gint) va_arg (args_copy, gint);
  arg2 = (gint) va_arg (args_copy, gint);

  va_end (args_copy);


  if (G_CCLOSURE_SWAP_DATA (closure))
    {
      data1 = closure->data;
      data2 = instance;
    }
  else
    {
      data1 = instance;
      data2 = closure->data;
    }
  callback = (GMarshalFunc_VOID__ENUM_INT_INT) (marshal_data ? marshal_data : cc->callback);

  callback (data1, arg0, arg1, arg2, data2); 
}



static void mywidget_constructed(GObject *object)
{
  g_print("mywidget_constructed.....\n");
    
  G_OBJECT_CLASS (mywidget_parent_class)->constructed (object);
  
  //skip
}



static void mywidget_finalize(GObject *object)
{
  g_print("mywidget_finalize.....\n");

  MyWidget *mywidget = MYWIDGET(object);
  MyWidgetPrivate *priv = mywidget->priv;

  g_clear_pointer (&priv->label_text, g_free);
  // g_free(priv->label_text);
  g_print("multipress_gesture=%p\n", priv->multipress_gesture);
  g_print("longpress_gesture=%p\n", priv->longpress_gesture);
  g_assert(priv->multipress_gesture);
  g_clear_object (&priv->multipress_gesture);
  g_clear_object (&priv->longpress_gesture);
  g_clear_object (&priv->drag_gesture);
  g_clear_object (&priv->key_event_controller);
  g_clear_object (&priv->motion_event_controller);
  g_clear_object (&priv->scroll_event_controller);

  G_OBJECT_CLASS(mywidget_parent_class)->finalize (object);

}



static void mywidget_set_property(GObject            *object,
                                  guint               prop_id,
                                  const GValue       *value,
                                  GParamSpec         *pspec)
{
  g_print("mywidget_set_property.....\n");

  MyWidget *mywidget = MYWIDGET(object);

  switch(prop_id)
  {
    case PROP_LABEL:
        mywidget_set_label(mywidget, g_value_get_string(value));
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;      
  }
}




static void mywidget_get_property(GObject            *object,
                                  guint               prop_id,
                                  GValue             *value,
                                  GParamSpec         *pspec)
{
  g_print("mywidget_get_property.....\n");

  MyWidget *mywidget = MYWIDGET(object);
  MyWidgetPrivate *priv = mywidget->priv;

  switch(prop_id)
  {
    case PROP_LABEL:
      g_value_set_string(value, priv->label_text);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;      
  }
}



static void mywidget_get_preferred_width(GtkWidget           *widget,
                                         gint                *minimum_size,
                                         gint                *natural_size)
{
  g_print("mywidget_get_preferred_width.....\n");
  GTK_WIDGET_CLASS(mywidget_parent_class)->get_preferred_width(widget, minimum_size, natural_size);  
}




static void mywidget_get_preferred_height(GtkWidget           *widget,
                                          gint                *minimum_size,
                                          gint                *natural_size)
{
  g_print("mywidget_get_preferred_height.....\n");
  GTK_WIDGET_CLASS(mywidget_parent_class)->get_preferred_height(widget, minimum_size, natural_size);  
}




static void mywidget_size_allocate(GtkWidget * widget, GtkAllocation * allocation)
{
  g_print("mywidget_size_allocate.....\n");
  GTK_WIDGET_CLASS(mywidget_parent_class)->size_allocate(widget, allocation);  
}



static void get_pattern_and_text(MyWidget *my_widget, cairo_pattern_t **pattern, gchar** text)
{  
  switch(my_widget->priv->last_type)
  {
    case GESTURE_SIG_BEGIN:
    case GESTURE_SIG_CANCEL:
    case GESTURE_SIG_END:
    case GESTURE_SIG_SEQUENCE_STATE_CHANGED:
    case GESTURE_SIG_UPDATE:
      *pattern = cairo_pattern_create_rgb(0,1,1);
      if(*text == NULL)
      {
        *text = "gesture now";
      }
      break;
      break;
    case GESTURE_SIG_MULTIPRESS_PRESSED:
    case GESTURE_SIG_MULTIPRESS_RELEASED:
    case GESTURE_SIG_MULTIPRESS_STOPPED:
      *pattern = cairo_pattern_create_rgb(1,0,0);
      if(*text == NULL)
      {
        *text = "mutlipress now";
      }
      break;

    case GESTURE_SIG_LONGPRESS_PRESSED:
    case GESTURE_SIG_LONGPRESS_CANCELLED:
      *pattern = cairo_pattern_create_rgb(0,1,0);
      if(*text == NULL)
      {
        *text = "longpress now";
      }
      break;
    case GESTURE_SIG_DRAG_BEGIN:
    case GESTURE_SIG_DRAG_UPDATE:
    case GESTURE_SIG_DRAG_END:
      *pattern = cairo_pattern_create_rgb(0,0,1);
      if(*text == NULL)
      {
        *text = "drag now";
      }
      break;
    case GESTURE_SIG_KEY_FOCUS_IN:
    case GESTURE_SIG_KEY_FOCUS_OUT:
    case GESTURE_SIG_KEY_IM_UPDATE:
    case GESTURE_SIG_KEY_PRESSED:
    case GESTURE_SIG_KEY_RELEASED:
    case GESTURE_SIG_KEY_MODIFIERS:
      *pattern = cairo_pattern_create_rgb(1,1,0);
      if(*text == NULL)
      {
        *text = "key evtCtrler now";
      }
      break;
    case GESTURE_SIG_SCROLL_DECELERATE:
    case GESTURE_SIG_SCROLL_BEGIN:
    case GESTURE_SIG_SCROLL_SCROLL:
    case GESTURE_SIG_SCROLL_END:
      *pattern = cairo_pattern_create_rgb(1,0,1);
      if(*text == NULL)
      {
        *text = "scroll evtCtrler now";
      }
      break;
    case GESTURE_SIG_MOTION_ENTER:
    case GESTURE_SIG_MOTION_MOTION:
    case GESTURE_SIG_MOTION_LEAVE:
      *pattern = cairo_pattern_create_rgb(0,0,1);
      if(*text == NULL)
      {
        *text = "motion evtCtrler now";
      }
      break;
    default:
      *pattern = cairo_pattern_create_rgb(0,0,0);
      if(*text == NULL)
      {
        *text = "default now";
      }
      break;
  }
}

static gint mywidget_draw(GtkWidget * widget, cairo_t *cr)
{
  g_print("mywidget_draw.....\n");

  MyWidget *mywidget = MYWIDGET(widget);

  cairo_save (cr);

  cairo_pattern_t *pattern;
  gchar* text = NULL;

  get_pattern_and_text(mywidget, &pattern, &text);
  g_print("text=%s\n", text);
  cairo_set_source(cr, pattern);
  cairo_pattern_destroy(pattern);
  // cairo_set_source_rgb(cr, 1, 0, 0);


  PangoLayout *layout;
  PangoFontDescription *desc;  

  layout = pango_cairo_create_layout (cr);

  desc = pango_font_description_from_string ("sans 12");
  pango_layout_set_font_description (layout, desc);
  pango_font_description_free (desc);

  pango_layout_set_width (layout, 600 * PANGO_SCALE);
  pango_layout_set_text (layout, text, -1);

  cairo_move_to(cr, 10, 10);


  pango_cairo_show_layout(cr, layout);

  cairo_restore(cr);
  g_object_unref (layout);

  return FALSE;     //GDK_EVENT_PROPAGATE
}




static void mywidget_realize(GtkWidget * widget)
{
  g_print("mywidget_realize.....\n");

  MyWidget *mywidget = MYWIDGET(widget);
  MyWidgetPrivate *priv = mywidget->priv;
  GtkAllocation allocation;
  GdkWindow *window;
  GdkWindowAttr attributes;
  gint attributes_mask;

  gtk_widget_set_realized (widget, TRUE);	
  
  window = gtk_widget_get_parent_window (widget);
  gtk_widget_set_window (widget, window);
  g_object_ref (window);


  gtk_widget_get_allocation (widget, &allocation);

  attributes.window_type = GDK_WINDOW_CHILD;	
  attributes.x = allocation.x;
  attributes.y = allocation.y;
  attributes.width = allocation.width;
  attributes.height = allocation.height;
  attributes.wclass = GDK_INPUT_ONLY;
  attributes.event_mask = gtk_widget_get_events (widget);
  attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
                            GDK_BUTTON_RELEASE_MASK |
                            GDK_TOUCH_MASK |
                            GDK_ENTER_NOTIFY_MASK |
                            GDK_LEAVE_NOTIFY_MASK);

  attributes_mask = GDK_WA_X | GDK_WA_Y;

  
	//以下创建inputOnly gdkwindow
  priv->event_window = gdk_window_new (window,  &attributes, attributes_mask);
  gtk_widget_register_window (widget, priv->event_window);	//zf, 指定 widget用于接收gdkevent
  // gtk_gesture_set_window (priv->multipress_gesture, priv->event_window);

}



static void mywidget_unrealize(GtkWidget * widget)
{
  g_print("mywidget_unrealize.....\n");
  MyWidget *mywidget = MYWIDGET(widget);
  MyWidgetPrivate *priv = mywidget->priv;

  if (priv->event_window)
  {
    gtk_widget_unregister_window (widget, priv->event_window);
    gdk_window_destroy (priv->event_window);
    priv->event_window = NULL;
  }

  GTK_WIDGET_CLASS(mywidget_parent_class)->unrealize (widget);
}



static void mywidget_map(GtkWidget * widget)
{
  g_print("mywidget_map.....\n");

  GTK_WIDGET_CLASS(mywidget_parent_class)->map(widget);

  MyWidget *mywidget = MYWIDGET(widget);
  MyWidgetPrivate *priv = mywidget->priv;

  if (priv->event_window)
    gdk_window_show(priv->event_window);
}



static void mywidget_unmap(GtkWidget * widget)
{
  g_print("mywidget_unmap.....\n");

  MyWidget *mywidget = MYWIDGET(widget);
  MyWidgetPrivate *priv = mywidget->priv;

  if (priv->event_window)
    gdk_window_hide(priv->event_window);

  GTK_WIDGET_CLASS(mywidget_parent_class)->unmap(widget);
}



static void mywidget_gesture_signal(MyWidget *mywidget, GestureSignalType sig_type, gint x, gint y)
{
  g_print("mywidget_gesture_signal.....\n");

  gchar* text;
  switch(sig_type)
  {
    case GESTURE_SIG_BEGIN:
      text = "gesture-begin";
      break;
    case GESTURE_SIG_CANCEL:
      text = "gesture-cancel";
      break;
    case GESTURE_SIG_END:
      text = "gesture-end";
      break;
    case GESTURE_SIG_SEQUENCE_STATE_CHANGED:
      text = "gesture-sequence-state-changed";
      break;
    case GESTURE_SIG_UPDATE:
      text = "gesture-update";
      break;

    case GESTURE_SIG_MULTIPRESS_PRESSED:
      text = "multipress-pressed";
      break;
    case GESTURE_SIG_MULTIPRESS_STOPPED:
      text = "multipress-stopped";
      break;
    case GESTURE_SIG_MULTIPRESS_RELEASED:
      text = "multipress-released";
      break;

    case GESTURE_SIG_LONGPRESS_PRESSED:
      text = "longpress-pressed";
      break;
    case GESTURE_SIG_LONGPRESS_CANCELLED:
      text = "longpress-cancelled";
      break;
    case GESTURE_SIG_DRAG_BEGIN:
      text = "drag-begin";
      break;
    case GESTURE_SIG_DRAG_UPDATE:
      text = "drag-update";
      break;
    case GESTURE_SIG_DRAG_END:
      text = "drag-end";
      break;
    case GESTURE_SIG_KEY_FOCUS_IN:
      text = "key-focus-in";
      break;
    case GESTURE_SIG_KEY_FOCUS_OUT:
      text = "key-focus-out";
      break;
    case GESTURE_SIG_KEY_IM_UPDATE:
      text = "key-im-update";
      break;
    case GESTURE_SIG_KEY_PRESSED:
      text = "key-pressed";
      break;
    case GESTURE_SIG_KEY_RELEASED:
      text = "key-released";
      break;
    case GESTURE_SIG_KEY_MODIFIERS:
      text = "key-modifiers";
      break;
    case GESTURE_SIG_SCROLL_DECELERATE:
      text = "scroll-decelerate";
      break;
    case GESTURE_SIG_SCROLL_BEGIN:
      text = "scroll-begin";
      break;
    case GESTURE_SIG_SCROLL_SCROLL:
      text = "scroll-scroll";
      break;
    case GESTURE_SIG_SCROLL_END:
      text = "scroll-end";
      break;
    case GESTURE_SIG_MOTION_ENTER:
      text = "motion-enter";
      break;
    case GESTURE_SIG_MOTION_MOTION:
      text = "motion-motion";
      break;
    case GESTURE_SIG_MOTION_LEAVE:
      text = "motion-leave";
      break;
    default:
      text = "default";
      break;
  }

  g_print("%s sig is triggerred\n", text);


  mywidget->priv->last_type = sig_type;

  gtk_widget_queue_draw(GTK_WIDGET(mywidget));
}





void mywidget_set_label(MyWidget *my_widget,  const gchar *label)
{
  g_return_if_fail (IS_MYWIDGET(my_widget));

  g_free(my_widget->priv->label_text);

  my_widget->priv->label_text = g_strdup(label);

  gtk_widget_queue_draw(GTK_WIDGET(my_widget));

  g_object_notify_by_pspec(G_OBJECT(my_widget), props[PROP_LABEL]);
}




const gchar *mywidget_get_label(MyWidget *my_widget)
{
  g_return_val_if_fail (IS_MYWIDGET(my_widget), NULL);

  return my_widget->priv->label_text;
}





static void	gesture_begin_cb(GtkGesture *gesture, GdkEventSequence *sequence, MyWidget *my_widget)
{
  g_print("gesture-begin........\n");
  gdouble x, y;

  gtk_gesture_get_point (gesture, sequence, &x, &y);
  g_signal_emit(my_widget, signals[GESTURE_SIGNAL], 0, GESTURE_SIG_BEGIN, x, y);
}



static void	gesture_cancel_cb(GtkGesture *gesture, GdkEventSequence *sequence, MyWidget *my_widget)
{
  g_print("gesture-cancel........\n");
  gdouble x, y;

  gtk_gesture_get_point (gesture, sequence, &x, &y);
  g_signal_emit(my_widget, signals[GESTURE_SIGNAL], 0, GESTURE_SIG_CANCEL, x, y);
}



static void	gesture_end_cb(GtkGesture *gesture, GdkEventSequence *sequence, MyWidget *my_widget)
{
  g_print("gesture-end........\n");
  
  gdouble x, y;

  gtk_gesture_get_point (gesture, sequence, &x, &y);
  g_signal_emit(my_widget, signals[GESTURE_SIGNAL], 0, GESTURE_SIG_END, x, y);
}




static void	gesture_sequence_state_changed_cb(GtkGesture *gesture, GdkEventSequence *sequence, GtkEventSequenceState state, MyWidget *my_widget)
{
  gdouble x = 0.0;
  gchar *text = "NONE";

  if(state == GTK_EVENT_SEQUENCE_CLAIMED)
  {
    x = 1.0;
    text = "CLAIMED";
  }
  else if(state == GTK_EVENT_SEQUENCE_DENIED)
  {
    x = -1.0;
    text = "DENIED";
  }

  g_print("gesture-state-changed (%s)........\n", text);;

  g_signal_emit(my_widget, signals[GESTURE_SIGNAL], 0, GESTURE_SIG_SEQUENCE_STATE_CHANGED, x, 0);
}



static void	gesture_update_cb(GtkGesture *gesture, GdkEventSequence *sequence, MyWidget *my_widget)
{
  gdouble x, y;

  gtk_gesture_get_point (gesture, sequence, &x, &y);

  g_print("gesture-update (x=%f,y=%f)........\n", x, y);

  g_signal_emit(my_widget, signals[GESTURE_SIGNAL], 0, GESTURE_SIG_UPDATE, x, y);
}                       





static void multipress_gesture_pressed_cb(GtkGestureMultiPress *gesture,
                       guint                 n_press,
                       gdouble               x,
                       gdouble               y,
                       MyWidget *my_widget)
{
  g_print("multipress-pressed (x=%f,y=%f)........\n", x, y);
  GtkWidget *widget = GTK_WIDGET(my_widget);

  if (gtk_widget_get_focus_on_click(widget) && !gtk_widget_has_focus(widget))
    gtk_widget_grab_focus (widget);

  g_signal_emit(my_widget, signals[GESTURE_SIGNAL], 0, GESTURE_SIG_MULTIPRESS_PRESSED, x, y);
  // gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
}                       


static void multipress_gesture_released_cb(GtkGestureMultiPress *gesture,
                        guint                 n_press,
                        gdouble               x,
                        gdouble               y,
                        MyWidget *my_widget)
{
  g_print("multipress-released (x=%f,y=%f)........\n", x, y);
  g_signal_emit(my_widget, signals[GESTURE_SIGNAL], 0, GESTURE_SIG_MULTIPRESS_RELEASED, x, y);
}                       



static void multipress_gesture_stopped_cb(GtkGestureMultiPress *gesture, MyWidget *my_widget)
{
  g_print("multipress-stopped....\n");
  g_signal_emit(my_widget, signals[GESTURE_SIGNAL], 0, GESTURE_SIG_MULTIPRESS_STOPPED, 0,0);
}                       




static void longpress_gesture_pressed_cb(GtkGestureLongPress *gesture, double x, double y, MyWidget *my_widget)
{
  g_print("longpress-pressed....\n");
  g_signal_emit(my_widget, signals[GESTURE_SIGNAL], 0, GESTURE_SIG_LONGPRESS_PRESSED, x, y);
}



static void longpress_gesture_cancelled_cb(GtkGestureLongPress *gesture, MyWidget *my_widget)
{
  g_print("longpress-cancelled....\n");
  g_signal_emit(my_widget, signals[GESTURE_SIGNAL], 0, GESTURE_SIG_LONGPRESS_CANCELLED, 0, 0);
}


static void drag_gesture_begin_cb(GtkGestureDrag *gesture, double start_x, double start_y, MyWidget *my_widget)
{
  g_print("drag-begin....\n");
  g_signal_emit(my_widget, signals[GESTURE_SIGNAL], 0, GESTURE_SIG_DRAG_BEGIN, start_x, start_y);
}


static void drag_gesture_update_cb(GtkGestureDrag *gesture, double offset_x, double offset_y, MyWidget *my_widget)
{
  gdouble start_x, start_y;

  gtk_gesture_drag_get_start_point (gesture, &start_x, &start_y);
  start_x += offset_x;
  start_y += offset_y;

  g_print("drag-update (x=%f, y=%f)....\n", start_x, start_y);
  g_signal_emit(my_widget, signals[GESTURE_SIGNAL], 0, GESTURE_SIG_DRAG_UPDATE, start_x, start_y);
}

static void drag_gesture_end_cb(GtkGestureDrag *gesture, double offset_x, double offset_y, MyWidget *my_widget)
{
  gdouble start_x, start_y;

  gtk_gesture_drag_get_start_point (gesture, &start_x, &start_y);
  start_x += offset_x;
  start_y += offset_y;

  g_print("drag-end (x=%f, y=%f)....\n", start_x, start_y);
  g_signal_emit(my_widget, signals[GESTURE_SIGNAL], 0, GESTURE_SIG_DRAG_END, start_x, start_y);
}


static void key_event_controller_focus_in_cb(GtkEventControllerKey *eventcontrollerkey, MyWidget *my_widget)
{
  g_print("key-focus-in....\n");
  g_signal_emit(my_widget, signals[GESTURE_SIGNAL], 0, GESTURE_SIG_KEY_FOCUS_IN, 0, 0);
}


static void key_event_controller_focus_out_cb(GtkEventControllerKey *eventcontrollerkey, MyWidget *my_widget)
{
  g_print("key-focus-out....\n");
  g_signal_emit(my_widget, signals[GESTURE_SIGNAL], 0, GESTURE_SIG_KEY_FOCUS_OUT, 0, 0);
}


static void key_event_controller_im_update_cb(GtkEventControllerKey *eventcontrollerkey, MyWidget *my_widget)
{
  g_print("key-im-update....\n");
  g_signal_emit(my_widget, signals[GESTURE_SIGNAL], 0, GESTURE_SIG_KEY_IM_UPDATE, 0, 0);
}



static gboolean key_event_controller_key_pressed_cb(GtkEventControllerKey *controller, 
                                              guint                  keyval,
                                              guint                  keycode,
                                              GdkModifierType        state,
                                              MyWidget              *my_widget)
{
  g_print("key-pressed....\n");
  g_signal_emit(my_widget, signals[GESTURE_SIGNAL], 0, GESTURE_SIG_KEY_PRESSED, 0, 0);
  return TRUE;
}


static gboolean key_event_controller_key_released_cb(GtkEventControllerKey *controller, 
                                              guint                  keyval,
                                              guint                  keycode,
                                              GdkModifierType        state,
                                              MyWidget              *my_widget)
{
  g_print("key-released....\n");
  g_signal_emit(my_widget, signals[GESTURE_SIGNAL], 0, GESTURE_SIG_KEY_RELEASED, 0, 0);
  return TRUE;
}


static gboolean key_event_controller_modifiers_cb(GtkEventControllerKey *eventcontrollerkey,
                                              GdkModifierType        arg1,
                                              MyWidget              *my_widget)
{
  g_print("key-modifiers....\n");
  g_signal_emit(my_widget, signals[GESTURE_SIGNAL], 0, GESTURE_SIG_KEY_MODIFIERS, 0, 0);
  return TRUE;
}


static void motion_event_controller_enter_cb(GtkEventControllerMotion *controller,
                                              double                    x,
                                              double                    y,
                                              MyWidget              *my_widget)
{
  g_print("motion-enter....\n");
  g_signal_emit(my_widget, signals[GESTURE_SIGNAL], 0, GESTURE_SIG_MOTION_ENTER, x, y);
}



static void motion_event_controller_leave_cb(GtkEventControllerMotion *controller, MyWidget *my_widget)
{
  g_print("motion-leave....\n");
  g_signal_emit(my_widget, signals[GESTURE_SIGNAL], 0, GESTURE_SIG_MOTION_LEAVE, 0, 0);
}


static void motion_event_controller_motion_cb(GtkEventControllerMotion *controller,
                                              double                    x,
                                              double                    y,
                                              MyWidget              *my_widget)
{
  g_print("motion-motion (x=%f, y=%f)....\n", x, y);
  g_signal_emit(my_widget, signals[GESTURE_SIGNAL], 0, GESTURE_SIG_MOTION_MOTION, x, y);
}


static void scroll_event_controller_decelerate_cb (GtkEventControllerScroll *controller,
                                              double                    vel_x,
                                              double                    vel_y,
                                              MyWidget              *my_widget)
{
  g_print("scroll-decelerate (vx=%f, vy=%f)....\n", vel_x, vel_y);
  g_signal_emit(my_widget, signals[GESTURE_SIGNAL], 0, GESTURE_SIG_SCROLL_DECELERATE, vel_x, vel_y);
}



static void scroll_event_controller_scroll_cb (GtkEventControllerScroll *controller,
                                              double                    dx,
                                              double                    dy,
                                              MyWidget              *my_widget)
{
  g_print("scroll-scroll (dx=%f, dy=%f)....\n", dx, dy);
  g_signal_emit(my_widget, signals[GESTURE_SIGNAL], 0, GESTURE_SIG_SCROLL_SCROLL, dx, dy);
}


static void scroll_event_controller_scroll_begin_cb (GtkEventControllerScroll *controller, MyWidget *my_widget)
{
  g_print("scroll-begin....\n");
  g_signal_emit(my_widget, signals[GESTURE_SIGNAL], 0, GESTURE_SIG_SCROLL_BEGIN, 0, 0);
}



static void scroll_event_controller_scroll_end_cb (GtkEventControllerScroll *controller, MyWidget *my_widget)
{
  g_print("scroll-end....\n");
  g_signal_emit(my_widget, signals[GESTURE_SIGNAL], 0, GESTURE_SIG_SCROLL_END, 0, 0);
}


